home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / networking / dumparpcache / dumparpcache.c next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  10.1 KB  |  333 lines

  1. /*
  2.     File:        DumpARPCache.c
  3.  
  4.     Contains:    Dumps the system ARP cache to stdout.
  5.  
  6.     Written by: Quinn "The Eskimo!"    
  7.  
  8.     Copyright:    Copyright © 1997-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 7/22/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 
  21.  
  22. */
  23.  
  24. #define qDebug 1
  25.  
  26. /////////////////////////////////////////////////////////////////////
  27. // Pick up the standard C stuff.
  28.  
  29. #include <stdio.h>
  30. #include <string.h>
  31.  
  32. /////////////////////////////////////////////////////////////////////
  33. // Pick up standard OT APIs.
  34.  
  35. #include <OpenTptInternet.h>
  36.  
  37. /////////////////////////////////////////////////////////////////////
  38. // Pick up low-level OT APIs.
  39.  
  40. #include <OpenTptClient.h>
  41. #include <OTDebug.h>
  42.  
  43. /////////////////////////////////////////////////////////////////////
  44. // Pick up the symbolic name of the various OT modules.
  45.  
  46. #include <modnames.h>
  47.  
  48. /////////////////////////////////////////////////////////////////////
  49. // OTDebugStr is not defined in any OT header files, but it is
  50. // exported by the libraries, so we define the prototype here.
  51.  
  52. extern pascal void OTDebugStr(const char* str);
  53.  
  54. /////////////////////////////////////////////////////////////////////
  55. // The following equates are actually exported by <miioccom.h>, but
  56. // they commented out for some reason )-:
  57.  
  58. // #include <miioccom.h>
  59.  
  60. #define MIOC_ND            'c'        /* ioctl's for Mentat's nd device */
  61.  
  62. // The following equates define the two "Name Dispatch" ioctls
  63. // for setting and getting OT internal parameters.
  64.  
  65. #define ND_GET            MIOC_CMD(MIOC_ND, 0)    /* Get a value */
  66. #define ND_SET            MIOC_CMD(MIOC_ND, 1)    /* Set a value */
  67.  
  68. /////////////////////////////////////////////////////////////////////
  69. // The name of the Name Dispatch variables we display.
  70.  
  71. #define ARP_ND_CACHE_REPORT     "arp_cache_report"
  72.     // ARP cache report
  73.  
  74. /////////////////////////////////////////////////////////////////////
  75.  
  76. /////////////////////////////////////////////////////////////////////
  77.  
  78. static OSStatus CreateStatusStream(StreamRef *result)
  79.     // Create a raw stream to which we can send the various
  80.     // status reports.  We do this by opening the IP driver,
  81.     // and pushing the other modules directly on top of it.
  82.     // This arrangement is just for convenience.  We could
  83.     // just have easily opened the null driver and pushed
  84.     // the module of interest on top.
  85. {
  86.     OSStatus err;
  87.     OSStatus junk;
  88.     StreamRef strm;
  89.     
  90.     // Open up a raw stream to the IP device.
  91.     
  92.     strm = OTStreamOpen(MI_IP_NAME, 0, &err);
  93.     if (err == noErr) {
  94.         // To make this simpler we're going to use sync/blocking mode.
  95.         
  96.         OTStreamSetBlocking(strm);
  97.         OTStreamSetSynchronous(strm);
  98.     }
  99.  
  100.     // Push the various modules of interest on top of the stream.
  101.     
  102.     if (err == noErr) {
  103.         err = OTStreamIoctl(strm, I_PUSH, MI_ARPM_NAME);
  104.     }
  105.     if (err == noErr) {
  106.         err = OTStreamIoctl(strm, I_PUSH, MI_TCPM_NAME);
  107.     }
  108.     if (err == noErr) {
  109.         err = OTStreamIoctl(strm, I_PUSH, MI_UDPM_NAME);
  110.     }
  111.     
  112.     // Clean up and setup result to either be valid or nil.
  113.     
  114.     if (err == noErr) {
  115.         *result = strm;
  116.     } else {
  117.         if (strm != kOTInvalidStreamRef) {
  118.             junk = OTStreamClose(strm);
  119.             OTAssert("CreateStatusStream: OTStreamClose failed", junk == noErr);
  120.         }
  121.         *result = kOTInvalidStreamRef;
  122.     }
  123.     return err;
  124. }
  125.  
  126. static void DumpNameDispatchReport(StreamRef strm, char *ndName, char *userVisibleName)
  127.     // Dumps a Name Dispatch (ND) report to standard out.  strm
  128.     // is a raw stream that contains the module from which the
  129.     // report is to be extracted.  ndName is the Name Dispatch
  130.     // name of the report.  userVisibleName is the name of the report
  131.     // in user terminology (only used to make the printout sensible).
  132.     //
  133.     // The general  principle is as follows.  We send an Name Dispatch ioctl
  134.     // down strm.  The relevant module catches the ioctl, creates the
  135.     // report (as text, with null characters as the line terminator)
  136.     // and sends it back to us.  The stream head copies the data back
  137.     // into our ioctl buffer.
  138.     //
  139.     // The only tricky thing is to judge the size of the buffer to
  140.     // allocate.  We do this in two passes.  In the first pass,
  141.     // we create a minimum sized buffer and use it for the ioctl.
  142.     // The ioctl result comes back as the size of the buffer we
  143.     // should have allocated.  We then reallocate the buffer
  144.     // and issue the ioctl again.  Obviously the size of the report
  145.     // could change between successive ioctls, so we have to
  146.     // loop until it works correctly.
  147. {
  148.     OSStatus err;
  149.     struct strioctl ndIoctl;
  150.     SInt32 i;
  151.     char *dataBuffer;
  152.     SInt32 dataBufferSize;
  153.     SInt32 minimumDataBufferSize;
  154.     SInt32 ioctlResult;
  155.     Boolean done;
  156.     
  157.     printf("Dumping %s (%s)\n\n", userVisibleName, ndName);
  158.     
  159.     // Allocate a minimum sized buffer for the first ioctl call.
  160.     // It's the length of the string, plus space for the null terminator,
  161.     // plus space for an extra null.
  162.     
  163.     dataBuffer = nil;
  164.     dataBufferSize = OTStrLength(ndName) + 1 + 1;
  165.     minimumDataBufferSize = dataBufferSize;
  166.     
  167.     done = false;
  168.     
  169.     do {
  170.         OTAssert("DumpNameDispatchReport: dataBuffer should have been disposed in the looping case", dataBuffer == nil);
  171.     
  172.         // Allocate the memory according to our current guess as to dataBufferSize.
  173.  
  174.         err = noErr;
  175.         dataBuffer = OTAllocMem( dataBufferSize );
  176.         if (dataBuffer == nil) {
  177.             err = kENOMEMErr;
  178.         }
  179.         
  180.         if (err == noErr) {
  181.  
  182.             // Copy the name of the ND variable we're trying
  183.             // to get into our buffer.
  184.  
  185.             OTStrCopy(dataBuffer, ndName);
  186.             
  187.             // Now put a null after the name in the data buffer.
  188.             // This is because ND requests must be made up
  189.             // of two strings, right after one another in the
  190.             // buffer.
  191.             
  192.             dataBuffer[ OTStrLength(ndName) + 1 ] = 0;
  193.         
  194.             // The ND_GET ioctl returns a value and sets ic_len.  A negative
  195.             // value is an error and you can give up now (-:  The rule for
  196.             // positive values is a bit weirder.  ic_len is always set
  197.             // to the amount of data that is actually returned.  If the
  198.             // data available exceeds the available buffer space (as
  199.             // defined by the ic_len on input), the ioctl returns
  200.             // a positive number that is the amount of buffer space
  201.             // needed.  So we first call it with a minimal buffer
  202.             // then give it the buffer space it requires.  Obviously
  203.             // there's a concurrency race here; we loop until our
  204.             // buffer is big enough.
  205.  
  206.             // First get the size of data buffer we need to allocate.
  207.             
  208.             ndIoctl.ic_cmd = ND_GET;
  209.             ndIoctl.ic_timout = 0;
  210.             ndIoctl.ic_len = dataBufferSize;
  211.             ndIoctl.ic_dp = dataBuffer;
  212.  
  213.             ioctlResult = OTStreamIoctl(strm, I_STR, &ndIoctl);
  214.             
  215.             // printf("••• dataBufferSize = %ld, ic_len = %ld, ioctlResult = %ld\n", dataBufferSize, ndIoctl.ic_len, ioctlResult);
  216.             
  217.             if (ioctlResult < 0) {
  218.                 err = ioctlResult;
  219.             } else {
  220.                 if (ioctlResult <= dataBufferSize) {
  221.                 
  222.                     // The report fit into dataBuffer, so let's
  223.                     // just print it out and we're done.  Remember that
  224.                     // the report uses nulls as line terminators, so we 
  225.                     // have to print it character by character )-:
  226.                     
  227.                     err = noErr;
  228.                     for (i = 0; i < ndIoctl.ic_len; i++) {
  229.                         if (dataBuffer[i] == 0) {
  230.                             putchar('\n');
  231.                         } else {
  232.                             putchar(dataBuffer[i]);
  233.                         }
  234.                     }
  235.                     done = true;
  236.                 } else {
  237.                 
  238.                     // The allocated data buffer is the wrong size,
  239.                     // so we deallocate and loop.
  240.                     
  241.                     OTAssert("DumpNameDispatchReport: Should have a data buffer here", dataBuffer != nil);
  242.                     OTFreeMem(dataBuffer);
  243.                     dataBuffer = nil;
  244.  
  245.                     // In this case, the ioctl has returned the size that
  246.                     // the buffer /should have been/ to get all the info.  We
  247.                     // set dataBufferSize to that value and loop.
  248.                     //
  249.                     // The buffer that we allocate should be able to hold
  250.                     // the request (ie the string (with null terminator)
  251.                     // and the second null).  If the ioctlResult comes
  252.                     // back too small, we're going to die when copying
  253.                     // the string into the new buffer.  However, the ioctlResult
  254.                     // should be bigger than the buffer, because otherwise it
  255.                     // wouldn't have failed.  So we just assert that
  256.                     // ioctlResult >= minimumDataBufferSize, just to be sure.
  257.  
  258.                     OTAssert("DumpNameDispatchReport: ioctl failed but it should have succeeded", ioctlResult >= minimumDataBufferSize);
  259.  
  260.                     dataBufferSize = ioctlResult;
  261.                 }
  262.             }
  263.         }
  264.     } while (err == noErr & ! done );
  265.     
  266.     // Clean up.
  267.     if (dataBuffer != nil) {
  268.         OTFreeMem(dataBuffer);
  269.     }
  270.     
  271.     if (err == noErr) {
  272.         printf("Success!\n");
  273.     } else {
  274.         printf("Failed with error %ld.\n", err);
  275.     }
  276.     printf("\n\n");
  277. }
  278.  
  279. /////////////////////////////////////////////////////////////////////
  280.  
  281. void main(void)
  282. {
  283.     OSStatus err;
  284.     OSStatus junk;
  285.     StreamRef strm;
  286.     InetInterfaceInfo junkInfo;
  287.     
  288.     printf("Hello Cruel World!\n");
  289.     printf("DumpARPCache -- Dumps the Open Transport ARP cache to stdout\n\n");
  290.     
  291.     err = InitOpenTransport();
  292.     
  293.     if (err == noErr) {
  294.     
  295.         err = OTInetGetInterfaceInfo(&junkInfo, kDefaultInetInterface);
  296.         if (err != noErr) {
  297.             printf("This report is not meaningful unless the TCP/IP stack is loaded.\n");
  298.             printf("You can still get the report, it just low on useful content.\n");
  299.             printf("\n");
  300.             err = noErr;
  301.         }
  302.         
  303.         if (err == noErr) {
  304.         
  305.             // Create the raw stream from which we're going to extract
  306.             // report information.  This stream contains all the TCP/IP
  307.             // modules ganged together in one convenient package.
  308.         
  309.             err = CreateStatusStream(&strm);
  310.             if (err == noErr) {
  311.             
  312.                 // Get and dump each report, one at a time.
  313.         
  314.                 DumpNameDispatchReport(strm, ARP_ND_CACHE_REPORT, "ARP Cache");
  315.                 
  316.                 // Clean up.
  317.                 
  318.                 junk = OTStreamClose(strm);
  319.                 OTAssert("main: OTStreamClose failed", junk == noErr);
  320.             }
  321.         }
  322.         
  323.         CloseOpenTransport();
  324.     }
  325.     
  326.     if (err == noErr) {
  327.         printf("Success.\n");
  328.     } else {
  329.         printf("Failed with error %d.\n", err);
  330.     }
  331.     printf("Done.  Press command-Q to Quit.\n");
  332. }
  333.